//
// Created by tongj on 2023/11/29.
//

#ifndef TBS_CPP_LOCK_HPP
#define TBS_CPP_LOCK_HPP

#include <base/base.hpp>
#include <mutex>
#include <atomic>
#include <base/log.hpp>

namespace tbs {
namespace lock {

constexpr static int COMMON_LOCK_TYPE = 0;

class BaseLock {
public:
  virtual bool lock(CONST int &sign = COMMON_LOCK_TYPE) = 0;

  virtual bool unlock(CONST int &sign = COMMON_LOCK_TYPE) = 0;

  virtual bool isLocked(CONST int &sign = COMMON_LOCK_TYPE) CONST = 0;

  BaseLock(CONST BaseLock &ref) = delete;

  BaseLock() = default;

  DESTRUCTION(BaseLock)
};

class MutexLock : public BaseLock {
public:

  virtual bool lock(CONST int &sign = COMMON_LOCK_TYPE) override;

  virtual bool unlock(CONST int &sign = COMMON_LOCK_TYPE) override;

  virtual bool isLocked(CONST int &sign = COMMON_LOCK_TYPE) CONST override;

private:
  std::mutex _mx;
  std::atomic_bool _is_lock{false};
};

class SpinLock : BaseLock {
public:
  bool lock(CONST int &sign = COMMON_LOCK_TYPE) override;

  bool unlock(const int &sign = COMMON_LOCK_TYPE) override;

  bool isLocked(const int &sign = COMMON_LOCK_TYPE) const override;

private:
  std::atomic<bool> _has_lock{false};
};

template<typename TL> inline static void COMMON_LOCKER_RELEASE(TL *tl);

template<typename TL> inline static void COMMON_LOCKER_LOCK(TL *tl);

template<typename TL> using CommonLockGuard = Guard<TL, COMMON_LOCKER_RELEASE, COMMON_LOCKER_LOCK>;

template<typename TL> CommonLockGuard<TL> make_lock_guard(TL &lock);

using MutexLockGuard = CommonLockGuard<MutexLock>;

using SpinLockGuard = CommonLockGuard<SpinLock>;

template<typename T> class WriteReadLock : public BaseLock {
public:
  constexpr static int READ_LOCK_TYPE = 1, WRITE_LOCK_TYPE = 2;

  inline static void WRITE_LOCK(WriteReadLock<T> *lk);
  inline static void WRITE_UNLOCK(WriteReadLock<T> *lk);

  inline static void READ_LOCK(WriteReadLock<T> *lk);

  inline static void READ_UNLOCK(WriteReadLock<T> *lk);

  WriteReadLock() = default;

  void readLock();

  void readUnlock();

  void writeLock();

  void writeUnlock();

  bool lock(CONST int &sign) override;

  bool unlock(CONST int &sign) override;

  bool isLocked(CONST int &sign) CONST override;

private:
  T _lock;
  std::atomic_int _readers{0}, _writers{0};
};

#include "inls/lock/WriteReadLock.cuh"

template<typename T> using ReadLockGuard = Guard<WriteReadLock<T>,
												 WriteReadLock<T>::READ_UNLOCK,
												 WriteReadLock<T>::READ_LOCK>;
template<typename T> using WriteLockGuard = Guard<WriteReadLock<T>,
												  WriteReadLock<T>::WRITE_UNLOCK,
												  WriteReadLock<T>::WRITE_LOCK>;

template<typename T> ReadLockGuard<T> make_read_lock_guard(WriteReadLock<T> &l);

template<typename T> WriteLockGuard<T> make_write_lock_guard(WriteReadLock<T> &l);

#include "inls/lock/lock.cuh"

}

}

#endif // TBS_CPP_LOCK_HPP
